KotlinとSwiftの拡張比較 (Swift 3.0対応)
まえがき
拡張の便利さを一度経験すると拡張なしでは生きていけないくらい、中毒性の高い機能です。
KotlinでAndroid開発していると、そのありがたさ、便利さをしみじみ感じます。
Swiftでも同じく拡張機能あったのでやってみました。
そもそも拡張って
このクラスにこんな機能があったらいいのに。っと思った時、以下の2つができると思います。
- クラスを継承して、サブクラスでメソッドを追加する
- Utilクラスを作り、staticメソッドを定義し、static importでメソッド呼び出し。
しかし、めんどくさいですよね。
それを簡単に作れる機能、それが拡張です!
簡単な拡張
Stringにlogメソッドを拡張して、printで表示するようにしてみましょう。
Kotlin
fun String.log() { print(this) } "test".log()
String. でStringに拡張することを宣言しています。
Swift
extension String { func log() { print(self) } } "test".log()
extensionでどれに拡張するか宣言し、以下に拡張メソッドを定義します
Genericsの拡張
具体的クラスの拡張は簡単でした。
Genericsの拡張をする場合はどうしたらよいでしょうか?
例えば、先程のlog()をすべてのクラスで使用できるように拡張する例でみてみます。
Kotlin
//Swiftに名前を合わせている.protocolの代わりにinterfaceを使う interface LoggableProtocol { fun string(): String //デフォルトの実装を定義できる //interfaceのメソッドを拡張で実装することはできない fun log() = print(string()) } //適応例 class Person(val name: String, val age: Int) : LoggableProtocol { override fun string() = "name: $name , age: $age" } val person = Person("kamedon", 20) // name: kamedon , age: 20 person.log() //Personのlogをextensionしてみると fun Person.log() { print("test") } // 上書きはされない // name: kamedon , age: 20 person.log()
※toStringはJavaにはありますが、Swiftにはないようです。そのため、Kotlinも toStringがないこと前提に書いています。
余談:Genericsの拡張とtoStringがすべてクラスで使えるので、これでできます。
fun <T> T.log() { print(toString()) }
- Kotlinの場合は、すでに定義されているメソッドや変数の拡張はできない。
- interfaceで定義してあるメソッドに拡張不可
- 変更する場合は、interfaceを敬称してるクラスでoverrideする必要がある。
- Genericsの拡張ができる
Swift
// 1.拡張したいメソッドをprotocolで記述する protocol LoggableProtocol { func string() -> String func log() } // 2.protocolには実装はかけないため、extensionで実装する extension LoggableProtocol { func log() { print(string()) } } // 3.実際に使用したいクラスに敬称させる class Person: LoggableProtocol { func string() -> String { return "name: \(name) , age: \(age)" } let name: String let age: Int init(name: String, age: Int) { self.name = name self.age = age } } //使用例 let person = Person(name: "kamedon", age: 20) // name: kamedon , age: 20 person.log() //Personのlogをextensionしてみると extension Person { func log() { print("test") } } //test person.log()
- Swiftはすでに定義されているメソッドも拡張で上書きすることできる
- protocolに実装を記述することはできないため、extensionで実装する
- Genericsの拡張を直接することができない
まとめ
interface と protocol, 拡張は似ていますが、できることが違います。
kotlinの拡張をSwiftで実現しようとすると詰まりやすいです。
protocolで定義、extensionで実装しないといけないケースがあり、少しややこしい印象です。
今回はメソッドのみ拡張しましたが、変数も拡張できますので、遊んでみてくださいね
最後に、拡張はオレオレ機能、オレオレ流儀が乱立し、何がなんだかわからなくなるときがあります。。。
用法用量を守って正しくお使いください。
動作環境
- kotlin: 1.0.4
- Swift: 3.0.1